import minimalmodbus
import serial
import time

class LE100485Sensor:
    def __init__(self, port='COM3', baudrate=115200, sensor_address=2, ser=None):
        """初始化传感器（支持共享外部串口或独立串口）"""
        self.sensor_address = sensor_address
        self.baudrate = baudrate
        self.external_ser = ser is not None  # 标记是否为共享串口

        # 优先使用外部传入的串口实例（共享模式）
        if ser is not None:
            self.ser = ser
            if self.ser.baudrate != baudrate:
                raise ValueError(f"共享串口波特率({self.ser.baudrate})与传感器要求({baudrate})不一致")
            self.instrument = minimalmodbus.Instrument(port=None, slaveaddress=sensor_address)
            self.instrument.serial = self.ser
        else:
            # 独立模式：创建专属串口
            self.instrument = minimalmodbus.Instrument(port, sensor_address)
            self.ser = self.instrument.serial

        # 强制配置串口参数（确保与传感器匹配）
        self.instrument.serial.baudrate = baudrate
        self.instrument.serial.bytesize = serial.EIGHTBITS
        self.instrument.serial.parity = serial.PARITY_NONE
        self.instrument.serial.stopbits = serial.STOPBITS_ONE
        self.instrument.serial.timeout = 2  # 延长超时时间，提升稳定性
        self.instrument.mode = minimalmodbus.MODE_RTU
        self.instrument.clear_buffers_before_each_transaction = True
        self.instrument.debug = False  # 如需调试，可设为True查看通信细节

        # 传感器核心配置（按手册确认）
        self.distance_register = 0x003B  # 距离值寄存器地址
        self.resolution = 0.001  # 分辨率1μm（0.001mm）

    def read_distance(self, register_address=None, number_of_registers=1):
        """读取距离数据，返回mm值（含详细错误日志）"""
        if register_address is None:
            register_address = self.distance_register
        try:
            print(f"[读取] 寄存器地址: 0x{register_address:04X}, 从机地址: {self.sensor_address}")
            raw_data = self.instrument.read_register(
                registeraddress=register_address,
                number_of_decimals=0,
                functioncode=3,
                signed=False
            )
            distance = raw_data * self.resolution
            print(f"[成功] 原始数据: {raw_data}, 转换后距离: {distance:.5f} mm")
            return distance
        except minimalmodbus.NoResponseError:
            print(f"[错误] 传感器无响应，请检查：1.接线是否正确 2.传感器是否上电 3.地址/波特率是否匹配")
            return None
        except minimalmodbus.ModbusException as e:
            print(f"[错误] Modbus通信异常: {str(e)}")
            return None
        except Exception as e:
            print(f"[错误] 读取失败: {str(e)}")
            return None

    def continuous_read(self, interval=0.5):
        """连续读取传感器数据，按Ctrl+C停止"""
        print(f"\n=== 激光位移传感器测试 ====")
        print(f"串口: {self.ser.port if self.ser.port else '共享串口'}")
        print(f"波特率: {self.baudrate}, 传感器地址: {self.sensor_address}")
        print(f"寄存器: 0x{self.distance_register:04X}, 分辨率: {self.resolution*1000} μm")
        print(f"开始连续读取（间隔{interval}秒），按Ctrl+C停止...\n")
        
        try:
            count = 0
            while True:
                count += 1
                print(f"==== 第{count}次读取 ====")
                distance = self.read_distance()
                if distance is None:
                    print("本次读取失败，等待下次重试...")
                time.sleep(interval)
        except KeyboardInterrupt:
            print("\n\n=== 连续读取已停止 ===")
        finally:
            self.close()

    def close(self):
        """关闭串口（共享模式不关闭，避免影响其他设备）"""
        if not self.external_ser and self.ser.is_open:
            self.ser.close()
            print(f"串口{self.ser.port}已关闭")
        elif self.external_ser:
            print("共享串口模式，不主动关闭串口")

if __name__ == "__main__":
    # -------------------------- 测试配置（根据实际情况修改）--------------------------
    TEST_PORT = "COM6"          # 传感器连接的串口号（如COM4、/dev/ttyUSB0）
    TEST_BAUDRATE = 115200      # 传感器波特率（默认115200，需与传感器一致）
    TEST_SENSOR_ADDR = 2        # 传感器地址（默认2，需与传感器配置一致）
    READ_INTERVAL = 0.5         # 连续读取间隔（秒）
    # --------------------------------------------------------------------------------

    # 初始化传感器（独立串口模式，专为测试设计）
    try:
        sensor = LE100485Sensor(
            port=TEST_PORT,
            baudrate=TEST_BAUDRATE,
            sensor_address=TEST_SENSOR_ADDR
        )
        # 开始连续读取测试
        sensor.continuous_read(interval=READ_INTERVAL)
    except ValueError as e:
        print(f"初始化失败: {str(e)}")
    except serial.SerialException as e:
        print(f"串口打开失败: {str(e)} | 请检查串口号是否正确、串口是否被占用")
    except Exception as e:
        print(f"测试异常: {str(e)}")